function [inputNames, varargout] = geninputsfromprj(prjFilePath, infDimSize, defFlt, defInt, defBool, defChar)
%GENINPUTSFROMPRJ 由代码生成工程文件生成入口函数的输入参数
%
% Input Arguments
% # prjFilePath: 字符串，代码生成工程文件（.prj）的路径
% # infDimSize: 标量，无上界维的尺寸，默认为1
% # defFlt, defInt, defBool, defChar: 分别为标量、整形标量、逻辑标量、字符，对应类型输入量的默认值，默认分别为NaN、0、true、‘ ’
%
% Output Arguments
% # inputNames: 长度与入口函数输入参数个数相同的元胞列向量，各元素为入口函数输入参数名
% # varargout: 可变数量输出参数，个数等于入口函数输入参数个数，分别为入口函数的各输入参数
%
% Assumptions and Limitations
% # 本函数针对R2014a版本的代码生成prj文件 TODO: add support for 2016a .prj files
% # 对于有上界的维数，尺寸按上界
% # embedded.fi类型的数据作为双精度浮点数处理

if nargin < 6
    defChar = ' ';
end
if nargin < 5
    defBool = true;
end
if nargin < 4
    defInt = 0;
end
if nargin < 3
    defFlt = NaN;
end
if nargin < 2
    infDimSize = 1;
end

% NOTE: 本函数使用线性索引

[DOMStruct] = parsexml(xmlread(prjFilePath));

DOMStruct = (DOMStruct.Children);
DOMStruct = DOMStruct(indByName(DOMStruct, 'configuration')).Children;
DOMStruct = DOMStruct(indByName(DOMStruct, 'fileset.entrypoints')).Children;
DOMStruct = DOMStruct(indByName(DOMStruct, 'file')).Children;
DOMStruct = DOMStruct(indByName(DOMStruct, 'Inputs')).Children;
DOMStruct = DOMStruct(indByName(DOMStruct, 'Input'));
inputNames = cell(length(DOMStruct), 1);
for i=1:length(DOMStruct)
    inputNames{i, 1} = DOMStruct(i).Attributes.Value;
    varargout{i} = genInput([], '', DOMStruct(i).Children, infDimSize, defFlt, defInt, defBool, defChar);
end
end

function ind = indByName(s, strName)
fcn = @(str) strcmp(str, strName);
ind = find(cellfun(fcn, {s.Name})); % 在s中查找Name域为'strName'的元素的序号
end

function [s] = genInput(s, fieldName, DOMStruct, infDimSize, defFlt, defInt, defBool, defChar)
class = DOMStruct(indByName(DOMStruct, 'Class')).Children.Data;
if strcmp(class, 'embedded.fi')
    class = 'double';
end
size = DOMStruct(indByName(DOMStruct, 'Size')).Children.Data;
size = strrep(lower(size), 'x', '');
size = strrep(size, ':', '');
size = str2num(strrep(size, 'inf', num2str(infDimSize)));
if ~isempty(indByName(DOMStruct, 'Complex')) ...
        && eval(DOMStruct(indByName(DOMStruct, 'Complex')).Children.Data)
    leftComplexExp = 'complex(';
    rightComplexExp = ')';
else
    leftComplexExp = '';
    rightComplexExp = '';
end
if isfield(DOMStruct(indByName(DOMStruct, 'Value')).Children, 'Data') % 如果已指定值则直接赋值，可以通过设置为constant或者define by example赋值
    sOrField = eval(DOMStruct(indByName(DOMStruct, 'Value')).Children.Data);
else % 如果没有指定值则从类型和尺寸生成默认值
    switch class
        case {'double', 'single'}
            sOrField = eval([leftComplexExp class '(defFlt*ones(size))' rightComplexExp]);
        case {'int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64'}
            sOrField = eval([leftComplexExp class '(defInt*ones(size))' rightComplexExp]);
        case 'logical'
            if defBool
                sOrField = true(size);
            else
                sOrField = false(size);
            end
        case 'char'
            sOrField = repmat(defChar, size);
        case 'struct'
            sOrField = struct;
            ind = indByName(DOMStruct, 'Field');
            for i=1:length(ind)
                subFieldName = DOMStruct(ind(i)).Attributes.Value;
                sOrField = genInput(sOrField, subFieldName, DOMStruct(ind(i)).Children, infDimSize, defFlt, defInt, defBool, defChar);
            end
            sOrField = repmat(sOrField, size);
        otherwise
            error('geninputsfromprj:unknownClass', 'Unknown input class.');
    end
end
if isempty(fieldName)
    s = sOrField;
else
    s.(fieldName) = sOrField;
end
end